package repository

import (
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/service/blog/model"

	"github.com/sirupsen/logrus"
	"github.com/volatiletech/null/v8"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/stores/cache"
)

type (
	// KBEntryRepository is an interface to be customized, add more methods here,
	// and implement the added methods in customKBEntryRepository.
	KBEntryRepository interface {
		FindOne(ctx context.Context, id uint64) (*model.BlogKnowledgeBasis, error)                 // ##24.12.05##
		FindOneByParentId(ctx context.Context, parentId uint64) (*model.BlogKnowledgeBasis, error) // ##24.12.05##
		FindOneWithExpire(
			ctx context.Context,
			id uint64,
			expire time.Duration,
		) (*model.BlogKnowledgeBasis, error) // ##24.12.05##
		FindOneNoCache(
			ctx context.Context,
			conn boil.ContextExecutor,
			id uint64,
		) (*model.BlogKnowledgeBasis, error) // ##24.12.05##
		GetList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBasis, int64, error) // ##24.12.05##
		Insert(
			ctx context.Context,
			tx boil.ContextExecutor,
			data *model.BlogKnowledgeBasis,
			rel *model.KBEntryRel,
		) error // ##24.12.05##
		Update(
			ctx context.Context,
			tx boil.ContextExecutor,
			data *model.BlogKnowledgeBasis,
			rel *model.KBEntryRel, // ##24.12.05##
		) error
		UpdateBatch(ctx context.Context, tx boil.ContextExecutor, ids []uint64, cols model.M) error
		SoftDelete(ctx context.Context, tx boil.ContextExecutor, id uint64) error
		Restore(ctx context.Context, tx boil.ContextExecutor, id uint64) error
		ForceDelete(ctx context.Context, tx boil.ContextExecutor, id uint64) error
		ForceDeleteBatch(ctx context.Context, tx boil.ContextExecutor, ids []uint64) error

		UpdateMeta(
			ctx context.Context,
			tx boil.ContextExecutor,
			metum *model.BlogKnowledgeBaseMetum,
			increment int32,
		) (int64, error)
		UpdateMediaBatch(
			ctx context.Context,
			tx boil.ContextExecutor,
			ids []uint64,
			cols model.M,
		) (int64, error)
		GetDetailList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBaseDetail, int64, error) // ##24.12.05##
		GetMedia(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogAttachmentRelationship, int64, error) // ##24.12.05##
		GetMeta(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBaseMetum, int64, error) // ##24.12.05##
		GetRelationshipList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogKnowledgeBaseRelationship, int64, error) // ##25.06.06##
		GetAttachmentRelationshipList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogAttachmentRelationship, int64, error) // ##24.11.08##
	}

	customKBEntryRepository struct {
		modelx.CachedConn
		mysqlConn           *sql.DB
		cacheIdPrefix       string
		cacheParentIdPrefix string
		cacheIdExpirePrefix string
	}
)

// NewKBEntryRepository returns a repository for the database table.
func NewKBEntryRepository(mysqlConn *sql.DB, cacheConf cache.CacheConf) KBEntryRepository {
	return &customKBEntryRepository{
		CachedConn:          modelx.NewConn(mysqlConn, cacheConf),
		mysqlConn:           mysqlConn,
		cacheIdPrefix:       "cache:blog:kb_entries:id:",
		cacheParentIdPrefix: "cache:blog:kb_entries:parent_id:",
		cacheIdExpirePrefix: "cache:blog:kb_entries:id:expire:",
	}
}

func (r *customKBEntryRepository) FindOne(
	ctx context.Context,
	id uint64,
) (*model.BlogKnowledgeBasis, error) {
	cacheIdKey := r.formatPrimary(id)
	var resp model.BlogKnowledgeBasis
	err := r.QueryCtx(ctx, &resp, cacheIdKey, func(ctx context.Context, conn *sql.DB, v any) error {
		data, err := model.FindBlogKnowledgeBasis(ctx, conn, id)
		if err != nil {
			return err
		}

		*v.(*model.BlogKnowledgeBasis) = *data

		return nil
	})

	switch err {
	case nil:
		return &resp, nil
	case sql.ErrNoRows:
		return nil, model.ErrNotFound
	default:
		return nil, err
	}
}

func (r *customKBEntryRepository) FindOneByParentId(
	ctx context.Context,
	parentId uint64,
) (*model.BlogKnowledgeBasis, error) {
	cacheParentIdKey := r.formatParentIdKey(parentId)
	var resp model.BlogKnowledgeBasis
	err := r.QueryRowIndexCtx(ctx, &resp, cacheParentIdKey, r.formatPrimary,
		func(ctx context.Context, conn *sql.DB, v any) (i any, e error) {
			mods := []qm.QueryMod{
				model.BlogKnowledgeBasisWhere.PostParentID.EQ(parentId),
			}
			list, err := model.BlogKnowledgeBases(mods...).All(ctx, conn)
			if err != nil {
				return nil, err
			}

			if len(list) > 0 {
				*v.(*model.BlogKnowledgeBasis) = *list[0]
				return list[0].ID, nil
			}

			return nil, model.ErrNotFound
		}, r.queryPrimary)

	switch err {
	case nil:
		return &resp, nil
	case sql.ErrNoRows:
		return nil, model.ErrNotFound
	default:
		return nil, err
	}
}

func (r *customKBEntryRepository) FindOneWithExpire(
	ctx context.Context,
	id uint64,
	expire time.Duration,
) (*model.BlogKnowledgeBasis, error) {
	cacheIdKey := r.formatPrimaryWithExpire(id)
	var resp model.BlogKnowledgeBasis
	err := r.QueryWithExpireCtx(ctx, &resp, cacheIdKey, expire, func(ctx context.Context, conn *sql.DB, v any) error {
		data, err := model.FindBlogKnowledgeBasis(ctx, conn, id)
		if err != nil {
			return err
		}

		*v.(*model.BlogKnowledgeBasis) = *data

		return nil
	})

	switch err {
	case nil:
		return &resp, nil
	case sql.ErrNoRows:
		return nil, model.ErrNotFound
	default:
		return nil, err
	}
}

func (r *customKBEntryRepository) FindOneNoCache(
	ctx context.Context,
	conn boil.ContextExecutor,
	id uint64,
) (*model.BlogKnowledgeBasis, error) {
	var db boil.ContextExecutor = r.mysqlConn
	if conn != nil {
		db = conn
	}
	data, err := model.FindBlogKnowledgeBasis(ctx, db, id)
	switch err {
	case nil:
		return data, nil
	case sql.ErrNoRows:
		return nil, model.ErrNotFound
	default:
		return nil, err
	}
}

func (r *customKBEntryRepository) GetList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBasis, count int64, err error) {
	var page int
	var pageSize int
	var limit int
	var selectCol string
	var mods []qm.QueryMod
	var nextCount int64
	var previousCount int64
	var statistic bool
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(uint64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(uint64); ok && val > 0 {
				pageSize = int(val)
			}
		case "limit":
			if val, ok := v.(uint32); ok && val > 0 {
				limit = int(val)
			}
		case "offset":
			if withCount == 2 {
				if val, ok := v.(uint32); ok && val > 0 {
					mods = append(mods, qm.Offset(int(val)))
					previousCount = 1
				}
			}
		case "orderBy":
			if val, ok := v.(string); ok && len(val) > 0 {
				mods = append(mods, qm.OrderBy(val))
			}
		case "preMinId":
			if withCount == 3 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBasisColumns.ID+" DESC"))
					mods = append(mods, model.BlogKnowledgeBasisWhere.ID.LT(val))
					previousCount = 1
				}
			}
		case "preMaxId":
			if withCount == 4 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBasisColumns.ID+" ASC"))
					mods = append(mods, model.BlogKnowledgeBasisWhere.ID.GT(val))
					previousCount = 1
				}
			}
		case "select":
			if withCount != 5 {
				if val, ok := v.(string); ok && len(val) > 0 {
					selectCol = val
				}
			}
		case "search":
			if val, ok := v.(string); ok && len(val) > 0 { // 搜索
				likeVal := fmt.Sprintf("%%%s%%", val)
				mods = append(mods, qm.Where(fmt.Sprintf(
					"(%s LIKE ? OR %s LIKE ?)",
					model.BlogKnowledgeBasisColumns.PostTitle,
					model.BlogKnowledgeBasisColumns.PostName), likeVal, likeVal))
			}
		case "statistic":
			if val, ok := v.(string); ok && val == "1" { // 按 Status 统计
				statistic = true
			}
		}
	}

	for key, opMap := range filter {
		switch key {
		case model.BlogKnowledgeBasisColumns.ID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.ID, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostAuthorID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.PostAuthorID, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostParentID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.PostParentID, opMap)...)
		case model.BlogKnowledgeBasisColumns.SectionID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.SectionID, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostTitle:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.PostTitle, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostExcerpt:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.PostExcerpt, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostName:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.PostName, opMap)...)
		case model.BlogKnowledgeBasisColumns.GUID:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBasisColumns.GUID, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostStatus:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.PostStatus, opMap)...)
		case model.BlogKnowledgeBasisColumns.CommentStatus:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.CommentStatus, opMap)...)
		case model.BlogKnowledgeBasisColumns.MenuOrder:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.MenuOrder, opMap)...)
		case model.BlogKnowledgeBasisColumns.StickyType:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.StickyType, opMap)...)
		case model.BlogKnowledgeBasisColumns.CommentCount:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBasisColumns.CommentCount, opMap)...)
		case model.BlogKnowledgeBasisColumns.PublicDate:
			mods = append(mods, modelx.GetTimeMods(model.BlogKnowledgeBasisColumns.PublicDate, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostDate:
			mods = append(mods, modelx.GetTimeMods(model.BlogKnowledgeBasisColumns.PostDate, opMap)...)
		case model.BlogKnowledgeBasisColumns.PostModifiedDate:
			mods = append(mods, modelx.GetTimeMods(model.BlogKnowledgeBasisColumns.PostModifiedDate, opMap)...)
		case model.BlogKnowledgeBasisColumns.DeletedAt:
			mods = append(mods, modelx.GetTimeMods(model.BlogKnowledgeBasisColumns.DeletedAt, opMap)...)
		}
	}

	if statistic {
		mods = append(mods, qm.Select(fmt.Sprintf(
			"%s, count(%s) as %s",
			model.BlogKnowledgeBasisColumns.PostStatus,
			model.BlogKnowledgeBasisColumns.PostStatus,
			model.BlogKnowledgeBasisColumns.MenuOrder,
		)))
		mods = append(mods, qm.GroupBy(model.BlogKnowledgeBasisColumns.PostStatus))
		preList, preErr := model.BlogKnowledgeBases(mods...).All(ctx, r.mysqlConn)
		if preErr != nil {
			err = preErr
			return
		}

		return preList, 0, nil
	}

	if withCount >= 2 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit+1))
		}
	} else if withCount >= 0 {
		count, err = model.BlogKnowledgeBases(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 && (withCount == -1 || withCount == 1) {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if len(selectCol) > 0 {
		if selectCol == "," {
			columns = append(columns, model.BlogKnowledgeBasisColumns.ID)
		} else {
			columns = strings.Split(selectCol, ",")
		}
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBases(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if withCount >= 2 {
		if limit > 0 && len(list) > limit {
			nextCount = 1
			list = list[:limit]
		}
		count = previousCount + nextCount*2
	}

	return
}

func (r *customKBEntryRepository) Insert(
	ctx context.Context,
	tx boil.ContextExecutor,
	data *model.BlogKnowledgeBasis,
	rel *model.KBEntryRel,
) error {
	err := r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
		var db boil.ContextExecutor
		if tx != nil {
			db = tx
		} else {
			db = conn
		}

		err := data.Insert(ctx, db, boil.Infer())
		if err != nil {
			return err
		}

		if rel == nil {
			return nil
		}

		entryId := data.ID

		if rel.Detail != nil {
			rel.Detail.KnowledgeBaseID = entryId
			err = rel.Detail.Insert(ctx, db, boil.Infer())
			if err != nil {
				return err
			}
		}

		if len(rel.Meta) > 0 {
			for _, v := range rel.Meta {
				v.KnowledgeBaseID = entryId
				err = v.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if len(rel.Media) > 0 {
			for _, v := range rel.Media {
				v.ObjectID = entryId
				v.ObjectType = uint16(globalkey.AttachmentLogTypeKnowledgeBase)
				err = v.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		objectType := uint16(globalkey.PostTypeKnowledgeBase)
		if len(rel.CategoryIds) > 0 {
			for _, tid := range rel.CategoryIds {
				var relationShip model.BlogTermRelationship
				relationShip.ObjectID = entryId
				relationShip.ObjectType = objectType
				relationShip.TermID = tid
				err = relationShip.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if len(rel.TagIds) > 0 {
			for _, tid := range rel.TagIds {
				var relationShip model.BlogTermRelationship
				relationShip.ObjectID = entryId
				relationShip.ObjectType = objectType
				relationShip.TermID = tid
				err = relationShip.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if rel.SectionId > 0 {
			var relationShip model.BlogTermRelationship
			relationShip.ObjectID = entryId
			relationShip.ObjectType = objectType
			relationShip.TermID = rel.SectionId
			relationShip.TermOrder = data.MenuOrder
			err = relationShip.Insert(ctx, db, boil.Infer())
			if err != nil {
				return err
			}
		}

		if len(rel.Term) > 0 {
			for _, v := range rel.Term {
				v.ObjectID = entryId
				v.ObjectType = uint16(globalkey.PostTypeKnowledgeBase)
				err = v.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if len(rel.Relations) > 0 {
			for _, v := range rel.Relations {
				v.FromEntryID = entryId
				err = v.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if len(rel.Versions) > 0 {
			for _, v := range rel.Versions {
				v.ToEntryID = entryId
				err = v.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		return nil
	}, r.getCacheKeys(data)...)

	return err
}

func (r *customKBEntryRepository) Update(
	ctx context.Context,
	tx boil.ContextExecutor,
	data *model.BlogKnowledgeBasis,
	rel *model.KBEntryRel,
) error {
	err := r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
		var db boil.ContextExecutor
		if tx != nil {
			db = tx
		} else {
			db = conn
		}

		if data != nil {
			blacklist := []string{
				model.BlogKnowledgeBasisColumns.ID,
				model.BlogKnowledgeBasisColumns.DeletedAt,
			}
			if rel != nil && len(rel.Blacklist) > 0 {
				blacklist = append(blacklist, rel.Blacklist...)
			}
			rowsAff, err := data.Update(ctx, db, boil.Blacklist(blacklist...))
			if err != nil {
				return err
			}

			if rowsAff == 0 {
				return model.ErrNotUpdated
			}
		}

		if rel == nil {
			return nil
		}

		entryId := data.ID
		if rel.Detail != nil {
			_, err := rel.Detail.Update(ctx, db, boil.Blacklist(
				model.BlogKnowledgeBaseDetailColumns.DetailID,
				model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID,
			))
			if err != nil {
				return err
			}
		}

		if len(rel.Meta) > 0 {
			for _, v := range rel.Meta {
				if v.MetaID > 0 {
					_, err := v.Update(ctx, db, boil.Blacklist(
						model.BlogKnowledgeBaseMetumColumns.MetaID,
						model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID,
						model.BlogKnowledgeBaseMetumColumns.MetaKey,
					))
					if err != nil {
						return err
					}
				} else {
					v.KnowledgeBaseID = entryId
					err := v.Insert(ctx, db, boil.Infer())
					if err != nil {
						return err
					}
				}
			}
		}

		if len(rel.Media) > 0 {
			for _, v := range rel.Media {
				if v.AttachmentRelationshipID > 0 {
					_, err := v.Update(ctx, db, boil.Blacklist(
						model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID,
						model.BlogAttachmentRelationshipColumns.ObjectID,
						model.BlogAttachmentRelationshipColumns.ObjectType,
					))
					if err != nil {
						return err
					}
				} else {
					v.ObjectID = entryId
					v.ObjectType = uint16(globalkey.AttachmentLogTypeKnowledgeBase)
					err := v.Insert(ctx, db, boil.Infer())
					if err != nil {
						return err
					}
				}
			}
		}

		if len(rel.CategoryIds) > 0 {
			for _, tid := range rel.CategoryIds {
				var relationShip model.BlogTermRelationship
				relationShip.ObjectID = entryId
				relationShip.ObjectType = uint16(globalkey.PostTypeKnowledgeBase)
				relationShip.TermID = tid
				err := relationShip.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if len(rel.TagIds) > 0 {
			for _, tid := range rel.TagIds {
				var relationShip model.BlogTermRelationship
				relationShip.ObjectID = entryId
				relationShip.ObjectType = uint16(globalkey.PostTypeKnowledgeBase)
				relationShip.TermID = tid
				err := relationShip.Insert(ctx, db, boil.Infer())
				if err != nil {
					return err
				}
			}
		}

		if len(rel.Term) > 0 {
			for _, v := range rel.Term {
				if v.TermRelationshipID > 0 {
					_, err := v.Update(ctx, db, boil.Blacklist(
						model.BlogTermRelationshipColumns.TermRelationshipID,
						model.BlogTermRelationshipColumns.ObjectID,
						model.BlogTermRelationshipColumns.ObjectType,
						model.BlogTermRelationshipColumns.TermID,
					))
					if err != nil {
						return err
					}
				} else {
					v.ObjectID = entryId
					v.ObjectType = uint16(globalkey.PostTypeKnowledgeBase)
					err := v.Insert(ctx, db, boil.Infer())
					if err != nil {
						return err
					}
				}
			}
		}

		if len(rel.Relations) > 0 {
			for _, v := range rel.Relations {
				if v.EntryRelationshipID > 0 {
					_, err := v.Update(ctx, db, boil.Blacklist(
						model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID,
						model.BlogKnowledgeBaseRelationshipColumns.FromEntryID,
						model.BlogKnowledgeBaseRelationshipColumns.FromSectionID,
					))
					if err != nil {
						return err
					}
				} else {
					v.FromEntryID = entryId
					err := v.Insert(ctx, db, boil.Infer())
					if err != nil {
						return err
					}
				}
			}
		}

		if len(rel.DelMetaIds) > 0 {
			var mods []qm.QueryMod
			mods = append(mods, model.BlogKnowledgeBaseMetumWhere.MetaID.IN(rel.DelMetaIds))
			_, err := model.BlogKnowledgeBaseMeta(mods...).DeleteAll(ctx, db)
			if err != nil {
				return err
			}
		}

		if len(rel.DelMediaIds) > 0 {
			var mods []qm.QueryMod
			mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentRelationshipID.IN(rel.DelMediaIds))
			_, err := model.BlogAttachmentRelationships(mods...).DeleteAll(ctx, db)
			if err != nil {
				return err
			}
		}

		if len(rel.DelTermIds) > 0 {
			var mods []qm.QueryMod
			mods = append(mods, model.BlogTermRelationshipWhere.TermRelationshipID.IN(rel.DelTermIds))
			_, err := model.BlogTermRelationships(mods...).DeleteAll(ctx, db)
			if err != nil {
				return err
			}
		}

		if len(rel.DelRelationIds) > 0 {
			var mods []qm.QueryMod
			mods = append(mods, model.BlogKnowledgeBaseRelationshipWhere.EntryRelationshipID.IN(rel.DelRelationIds))
			_, err := model.BlogKnowledgeBaseRelationships(mods...).DeleteAll(ctx, db)
			if err != nil {
				return err
			}
		}

		return nil
	}, r.getCacheKeys(data)...)

	return err
}

func (r *customKBEntryRepository) UpdateBatch(
	ctx context.Context,
	tx boil.ContextExecutor,
	ids []uint64,
	cols model.M,
) error {
	if len(ids) > 0 {
		err := r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
			var db boil.ContextExecutor
			if tx != nil {
				db = tx
			} else {
				db = conn
			}

			var mods []qm.QueryMod
			mods = append(mods, model.BlogKnowledgeBasisWhere.ID.IN(ids))
			rowsAff, err := model.BlogKnowledgeBases(mods...).UpdateAll(ctx, db, cols)
			if err != nil {
				return err
			}

			if rowsAff == 0 {
				return model.ErrNotUpdated
			}

			return nil
		}, r.formatPrimaries(ids)...)

		return err
	}

	return nil
}

func (r *customKBEntryRepository) SoftDelete(
	ctx context.Context,
	tx boil.ContextExecutor,
	id uint64,
) error {
	data, err := r.FindOneNoCache(ctx, tx, id)
	if err != nil {
		if err == model.ErrNotFound {
			return nil
		}

		return err
	}

	if data.PostStatus == uint16(globalkey.PostStatusTrash) {
		return nil
	}

	data.DelStatus = data.PostStatus
	data.PostStatus = uint16(globalkey.PostStatusTrash)
	data.DeletedAt = null.TimeFrom(time.Now())
	err = r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
		var db boil.ContextExecutor
		if tx != nil {
			db = tx
		} else {
			db = conn
		}

		rowsAff, err := data.Update(ctx, db, boil.Whitelist(
			model.BlogKnowledgeBasisColumns.DelStatus,
			model.BlogKnowledgeBasisColumns.PostStatus,
			model.BlogKnowledgeBasisColumns.DeletedAt,
		))
		if err != nil {
			return err
		}

		if rowsAff == 0 {
			return model.ErrNotUpdated
		}

		return nil
	}, r.getCacheKeys(data)...)

	return err
}

func (r *customKBEntryRepository) Restore(
	ctx context.Context,
	tx boil.ContextExecutor,
	id uint64,
) error {
	data, err := r.FindOneNoCache(ctx, tx, id)
	if err != nil {
		if err == model.ErrNotFound {
			return nil
		}

		return err
	}

	if data.PostStatus != uint16(globalkey.PostStatusTrash) {
		return nil
	}

	data.PostStatus = data.DelStatus
	data.DeletedAt = null.TimeFromPtr(nil)
	err = r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
		var db boil.ContextExecutor
		if tx != nil {
			db = tx
		} else {
			db = conn
		}

		rowsAff, err := data.Update(ctx, db, boil.Whitelist(
			model.BlogKnowledgeBasisColumns.PostStatus,
			model.BlogKnowledgeBasisColumns.DeletedAt,
		))
		if err != nil {
			return err
		}

		if rowsAff == 0 {
			return model.ErrNotUpdated
		}

		return nil
	}, r.getCacheKeys(data)...)

	return err
}

func (r *customKBEntryRepository) ForceDelete(
	ctx context.Context,
	tx boil.ContextExecutor,
	id uint64,
) error {
	data, err := r.FindOneNoCache(ctx, tx, id)
	if err != nil {
		if err == model.ErrNotFound {
			return nil
		}

		return err
	}

	err = r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
		var db boil.ContextExecutor
		if tx != nil {
			db = tx
		} else {
			db = conn
		}

		rowsAff, err := data.Delete(ctx, db)
		if err != nil {
			return err
		}

		if rowsAff == 0 {
			return model.ErrNotDeleted
		}

		return nil
	}, r.getCacheKeys(data)...)

	return err
}

func (r *customKBEntryRepository) ForceDeleteBatch(
	ctx context.Context,
	tx boil.ContextExecutor,
	ids []uint64,
) error {
	if len(ids) > 0 {
		err := r.ExecCtx(ctx, func(ctx context.Context, conn *sql.DB) error {
			var db boil.ContextExecutor
			if tx != nil {
				db = tx
			} else {
				db = conn
			}

			var mods []qm.QueryMod
			mods = append(mods, model.BlogKnowledgeBasisWhere.ID.IN(ids))

			rowsAff, err := model.BlogKnowledgeBases(mods...).DeleteAll(ctx, db)
			if err != nil {
				return err
			}

			if rowsAff == 0 {
				return model.ErrNotDeleted
			}

			return nil
		}, r.formatPrimaries(ids)...)

		return err
	}

	return nil
}

func (r *customKBEntryRepository) getCacheKeys(data *model.BlogKnowledgeBasis) []string {
	if data == nil {
		return []string{}
	}

	cacheIdKey := r.formatPrimary(data.ID)
	cacheIdExpireKey := r.formatPrimaryWithExpire(data.ID)
	cacheParentIdKey := r.formatParentIdKey(data.PostParentID)
	cacheKeys := []string{
		cacheIdKey,
		cacheIdExpireKey,
		cacheParentIdKey,
	}

	return cacheKeys
}

func (r *customKBEntryRepository) formatPrimary(primary any) string {
	return fmt.Sprintf("%s%v", r.cacheIdPrefix, primary)
}

func (r *customKBEntryRepository) formatPrimaryWithExpire(primary any) string {
	return fmt.Sprintf("%s%v", r.cacheIdExpirePrefix, primary)
}

func (r *customKBEntryRepository) formatPrimaries(primaries []uint64) []string {
	var resp []string
	for _, primary := range primaries {
		resp = append(resp, r.formatPrimary(primary))
		resp = append(resp, r.formatPrimaryWithExpire(primary))
	}

	return resp
}

func (r *customKBEntryRepository) formatParentIdKey(parentId uint64) string {
	return fmt.Sprintf("%s%d", r.cacheParentIdPrefix, parentId)
}

// func (r *customKBEntryRepository) queryPrimary(ctx context.Context, conn *sql.DB, v, primary any) error {
// 	data, err := model.FindBlogKnowledgeBasis(ctx, conn, primary.(uint64))
// 	if err != nil {
// 		return err
// 	}

// 	*v.(*model.BlogKnowledgeBasis) = *data

// 	return nil
// }

func (r *customKBEntryRepository) queryPrimary(ctx context.Context, conn *sql.DB, v any, primary any) error {
	var eid uint64
	if jsonId, ok := primary.(json.Number); ok {
		if int64Id, err := jsonId.Int64(); err == nil {
			eid = uint64(int64Id)
		} else {
			return err
		}
	}

	data, err := model.FindBlogKnowledgeBasis(ctx, conn, eid)
	if err != nil {
		return err
	}

	*v.(*model.BlogKnowledgeBasis) = *data

	return nil
}

func (r *customKBEntryRepository) GetDetailList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBaseDetail, count int64, err error) {
	var page int
	var pageSize int
	var limit int
	var selectCol string
	var mods []qm.QueryMod
	var nextCount int64
	var previousCount int64
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(uint64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(uint64); ok && val > 0 {
				pageSize = int(val)
			}
		case "limit":
			if val, ok := v.(uint32); ok && val > 0 {
				limit = int(val)
			}
		case "offset":
			if withCount == 2 {
				if val, ok := v.(uint32); ok && val > 0 {
					mods = append(mods, qm.Offset(int(val)))
					previousCount = 1
				}
			}
		case "orderBy":
			if val, ok := v.(string); ok && len(val) > 0 {
				mods = append(mods, qm.OrderBy(val))
			}
		case "preMinId":
			if withCount == 3 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBaseDetailColumns.DetailID+" DESC"))
					mods = append(mods, model.BlogKnowledgeBaseDetailWhere.DetailID.LT(val))
					previousCount = 1
				}
			}
		case "preMaxId":
			if withCount == 4 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBaseDetailColumns.DetailID+" ASC"))
					mods = append(mods, model.BlogKnowledgeBaseDetailWhere.DetailID.GT(val))
					previousCount = 1
				}
			}
		case "select":
			if withCount != 5 {
				if val, ok := v.(string); ok && len(val) > 0 {
					selectCol = val
				}
			}
		}
	}

	for key, opMap := range filter {
		switch key {
		case model.BlogKnowledgeBaseDetailColumns.DetailID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseDetailColumns.DetailID, opMap)...)
		case model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID, opMap)...)
		}
	}

	if withCount >= 2 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit+1))
		}
	} else if withCount >= 0 {
		count, err = model.BlogKnowledgeBaseDetails(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 && (withCount == -1 || withCount == 1) {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if len(selectCol) > 0 {
		if selectCol == "," {
			columns = append(columns, model.BlogKnowledgeBaseDetailColumns.DetailID)
		} else {
			columns = strings.Split(selectCol, ",")
		}
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBaseDetails(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if withCount >= 2 {
		if limit > 0 && len(list) > limit {
			nextCount = 1
			list = list[:limit]
		}
		count = previousCount + nextCount*2
	}

	return
}

func (r *customKBEntryRepository) GetMedia(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogAttachmentRelationship, count int64, err error) {
	var page int
	var pageSize int
	var limit int
	var selectCol string
	var mods []qm.QueryMod
	var nextCount int64
	var previousCount int64
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(uint64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(uint64); ok && val > 0 {
				pageSize = int(val)
			}
		case "limit":
			if val, ok := v.(uint32); ok && val > 0 {
				limit = int(val)
			}
		case "offset":
			if withCount == 2 {
				if val, ok := v.(uint32); ok && val > 0 {
					mods = append(mods, qm.Offset(int(val)))
					previousCount = 1
				}
			}
		case "orderBy":
			if val, ok := v.(string); ok && len(val) > 0 {
				mods = append(mods, qm.OrderBy(val))
			}
		case "preMinId":
			if withCount == 3 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID+" DESC"))
					mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentRelationshipID.LT(val))
					previousCount = 1
				}
			}
		case "preMaxId":
			if withCount == 4 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID+" ASC"))
					mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentRelationshipID.GT(val))
					previousCount = 1
				}
			}
		case "select":
			if withCount != 5 {
				if val, ok := v.(string); ok && len(val) > 0 {
					selectCol = val
				}
			}
		}
	}

	for key, opMap := range filter {
		switch key {
		case model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID, opMap)...)
		case model.BlogAttachmentRelationshipColumns.ObjectID:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectID, opMap)...)
		case model.BlogAttachmentRelationshipColumns.ObjectType:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectType, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentID:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentID, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentThumbnail:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentThumbnail, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentOrder:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentOrder, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentSource:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentSource, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentImageURL:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentImageURL, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentImageAlt:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentImageAlt, opMap)...)
		}
	}

	if withCount >= 2 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit+1))
		}
	} else if withCount >= 0 {
		count, err = model.BlogAttachmentRelationships(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 && (withCount == -1 || withCount == 1) {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if len(selectCol) > 0 {
		if selectCol == "," {
			columns = append(columns, model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID)
		} else {
			columns = strings.Split(selectCol, ",")
		}
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogAttachmentRelationships(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if withCount >= 2 {
		if limit > 0 && len(list) > limit {
			nextCount = 1
			list = list[:limit]
		}
		count = previousCount + nextCount*2
	}

	return
}

func (r *customKBEntryRepository) GetMeta(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBaseMetum, count int64, err error) {
	var page int
	var pageSize int
	var limit int
	var selectCol string
	var mods []qm.QueryMod
	var nextCount int64
	var previousCount int64
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(uint64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(uint64); ok && val > 0 {
				pageSize = int(val)
			}
		case "limit":
			if val, ok := v.(uint32); ok && val > 0 {
				limit = int(val)
			}
		case "offset":
			if withCount == 2 {
				if val, ok := v.(uint32); ok && val > 0 {
					mods = append(mods, qm.Offset(int(val)))
					previousCount = 1
				}
			}
		case "orderBy":
			if val, ok := v.(string); ok && len(val) > 0 {
				mods = append(mods, qm.OrderBy(val))
			}
		case "preMinId":
			if withCount == 3 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBaseMetumColumns.MetaID+" DESC"))
					mods = append(mods, model.BlogKnowledgeBaseMetumWhere.MetaID.LT(val))
					previousCount = 1
				}
			}
		case "preMaxId":
			if withCount == 4 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBaseMetumColumns.MetaID+" ASC"))
					mods = append(mods, model.BlogKnowledgeBaseMetumWhere.MetaID.GT(val))
					previousCount = 1
				}
			}
		case "select":
			if withCount != 5 {
				if val, ok := v.(string); ok && len(val) > 0 {
					selectCol = val
				}
			}
		}
	}

	for key, opMap := range filter {
		switch key {
		case model.BlogKnowledgeBaseMetumColumns.MetaID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseMetumColumns.MetaID, opMap)...)
		case model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID, opMap)...)
		case model.BlogKnowledgeBaseMetumColumns.MetaKey:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBaseMetumColumns.MetaKey, opMap)...)
		case model.BlogKnowledgeBaseMetumColumns.MetaValue:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBaseMetumColumns.MetaValue, opMap)...)
		}
	}

	if withCount >= 2 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit+1))
		}
	} else if withCount >= 0 {
		count, err = model.BlogKnowledgeBaseMeta(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 && (withCount == -1 || withCount == 1) {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if len(selectCol) > 0 {
		if selectCol == "," {
			columns = append(columns, model.BlogKnowledgeBaseMetumColumns.MetaID)
		} else {
			columns = strings.Split(selectCol, ",")
		}
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBaseMeta(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if withCount >= 2 {
		if limit > 0 && len(list) > limit {
			nextCount = 1
			list = list[:limit]
		}
		count = previousCount + nextCount*2
	}

	return
}

func (r *customKBEntryRepository) GetRelationshipList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogKnowledgeBaseRelationship, count int64, err error) {
	var page int
	var pageSize int
	var limit int
	var selectCol string
	var mods []qm.QueryMod
	var nextCount int64
	var previousCount int64
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(uint64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(uint64); ok && val > 0 {
				pageSize = int(val)
			}
		case "limit":
			if val, ok := v.(uint32); ok && val > 0 {
				limit = int(val)
			}
		case "offset":
			if withCount == 2 {
				if val, ok := v.(uint32); ok && val > 0 {
					mods = append(mods, qm.Offset(int(val)))
					previousCount = 1
				}
			}
		case "orderBy":
			if val, ok := v.(string); ok && len(val) > 0 {
				mods = append(mods, qm.OrderBy(val))
			}
		case "preMinId":
			if withCount == 3 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID+" DESC"))
					mods = append(mods, model.BlogKnowledgeBaseRelationshipWhere.EntryRelationshipID.LT(val))
					previousCount = 1
				}
			}
		case "preMaxId":
			if withCount == 4 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID+" ASC"))
					mods = append(mods, model.BlogKnowledgeBaseRelationshipWhere.EntryRelationshipID.GT(val))
					previousCount = 1
				}
			}
		case "select":
			if withCount != 5 {
				if val, ok := v.(string); ok && len(val) > 0 {
					selectCol = val
				}
			}
		}
	}

	for key, opMap := range filter {
		switch key {
		case model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.FromEntryID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.FromEntryID, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.FromSectionID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.FromSectionID, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.ToEntryID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryID, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.ToSectionID:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToSectionID, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.ToEntryGroup:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryGroup, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.ToEntryOrder:
			mods = append(mods, modelx.GetIntMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryOrder, opMap)...)
		case model.BlogKnowledgeBaseRelationshipColumns.ToEntryMeta:
			mods = append(mods, modelx.GetStringMods(model.BlogKnowledgeBaseRelationshipColumns.ToEntryMeta, opMap)...)
		}
	}

	if withCount >= 2 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit+1))
		}
	} else if withCount >= 0 {
		count, err = model.BlogKnowledgeBaseRelationships(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 && (withCount == -1 || withCount == 1) {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if len(selectCol) > 0 {
		if selectCol == "," {
			columns = append(columns, model.BlogKnowledgeBaseRelationshipColumns.EntryRelationshipID)
		} else {
			columns = strings.Split(selectCol, ",")
		}
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogKnowledgeBaseRelationships(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if withCount >= 2 {
		if limit > 0 && len(list) > limit {
			nextCount = 1
			list = list[:limit]
		}
		count = previousCount + nextCount*2
	}

	return
}

func (r *customKBEntryRepository) UpdateMeta(
	ctx context.Context,
	tx boil.ContextExecutor,
	metum *model.BlogKnowledgeBaseMetum,
	increment int32,
) (rowsAff int64, err error) {
	var db boil.ContextExecutor = r.mysqlConn
	if tx != nil {
		db = tx
	}

	var mods []qm.QueryMod
	mods = append(mods, model.BlogKnowledgeBaseMetumWhere.KnowledgeBaseID.EQ(metum.KnowledgeBaseID))
	mods = append(mods, model.BlogKnowledgeBaseMetumWhere.MetaKey.EQ(metum.MetaKey))
	list, err := model.BlogKnowledgeBaseMeta(mods...).All(ctx, db)
	if err != nil {
		logrus.Info(fmt.Sprintf("UpdateMeta error, err: %+v", err))
		if err == model.ErrNotFound {
			err = metum.Insert(ctx, db, boil.Infer())
			return 1, err
		}

		return 0, err
	}

	if len(list) == 0 {
		err = metum.Insert(ctx, db, boil.Infer())
		return 1, err
	}

	if increment > 0 {
		var info RandomInfo
		err = queries.Raw(fmt.Sprintf(
			`update %s set %s=%s+%s where %s="%d" and %s="%s"`,
			model.TableNames.BlogKnowledgeBaseMeta,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			metum.MetaValue.String,
			model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID,
			metum.KnowledgeBaseID,
			model.BlogKnowledgeBaseMetumColumns.MetaKey,
			metum.MetaKey,
		)).Bind(ctx, db, &info)
	} else if increment < 0 {
		var info RandomInfo
		err = queries.Raw(fmt.Sprintf(
			`update %s set %s=%s-%s where %s="%d" and %s="%s"`,
			model.TableNames.BlogKnowledgeBaseMeta,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			model.BlogKnowledgeBaseMetumColumns.MetaValue,
			metum.MetaValue.String,
			model.BlogKnowledgeBaseMetumColumns.KnowledgeBaseID,
			metum.KnowledgeBaseID,
			model.BlogKnowledgeBaseMetumColumns.MetaKey,
			metum.MetaKey,
		)).Bind(ctx, db, &info)
	} else {
		_, err = model.BlogKnowledgeBaseMeta(mods...).UpdateAll(ctx, db, model.M{
			model.BlogKnowledgeBaseMetumColumns.MetaValue: metum.MetaValue,
		})
	}

	return 1, err
}

func (r *customKBEntryRepository) UpdateMediaBatch(
	ctx context.Context,
	tx boil.ContextExecutor,
	ids []uint64,
	cols model.M,
) (rowsAff int64, err error) {
	if len(ids) > 0 {
		var db boil.ContextExecutor
		if tx != nil {
			db = tx
		} else {
			db = r.mysqlConn
		}

		var mods []qm.QueryMod
		mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentRelationshipID.IN(ids))
		rowsAff, err = model.BlogAttachmentRelationships(mods...).UpdateAll(ctx, db, cols)
	}

	return
}

func (r *customKBEntryRepository) GetAttachmentRelationshipList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogAttachmentRelationship, count int64, err error) {
	var page int
	var pageSize int
	var limit int
	var selectCol string
	var mods []qm.QueryMod
	var nextCount int64
	var previousCount int64
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(uint64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(uint64); ok && val > 0 {
				pageSize = int(val)
			}
		case "limit":
			if val, ok := v.(uint32); ok && val > 0 {
				limit = int(val)
			}
		case "offset":
			if withCount == 2 {
				if val, ok := v.(uint32); ok && val > 0 {
					mods = append(mods, qm.Offset(int(val)))
					previousCount = 1
				}
			}
		case "orderBy":
			if val, ok := v.(string); ok && len(val) > 0 {
				mods = append(mods, qm.OrderBy(val))
			}
		case "preMinId":
			if withCount == 3 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID+" DESC"))
					mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentRelationshipID.LT(val))
					previousCount = 1
				}
			}
		case "preMaxId":
			if withCount == 4 {
				if val, ok := v.(uint64); ok && val > 0 {
					mods = append(mods, qm.OrderBy(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID+" ASC"))
					mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentRelationshipID.GT(val))
					previousCount = 1
				}
			}
		case "select":
			if withCount != 5 {
				if val, ok := v.(string); ok && len(val) > 0 {
					selectCol = val
				}
			}
		}
	}

	for key, opMap := range filter {
		switch key {
		case model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID, opMap)...)
		case model.BlogAttachmentRelationshipColumns.ObjectID:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectID, opMap)...)
		case model.BlogAttachmentRelationshipColumns.ObjectType:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectType, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentID:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentID, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentThumbnail:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentThumbnail, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentOrder:
			mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentOrder, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentSource:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentSource, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentImageURL:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentImageURL, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentImageAlt:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentImageAlt, opMap)...)
		case model.BlogAttachmentRelationshipColumns.AttachmentImageMeta:
			mods = append(mods, modelx.GetStringMods(model.BlogAttachmentRelationshipColumns.AttachmentImageMeta, opMap)...)
		}
	}

	if withCount >= 2 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit+1))
		}
	} else if withCount >= 0 {
		count, err = model.BlogAttachmentRelationships(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 && (withCount == -1 || withCount == 1) {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if len(selectCol) > 0 {
		if selectCol == "," {
			columns = append(columns, model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID)
		} else {
			columns = strings.Split(selectCol, ",")
		}
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogAttachmentRelationships(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if withCount >= 2 {
		if limit > 0 && len(list) > limit {
			nextCount = 1
			list = list[:limit]
		}
		count = previousCount + nextCount*2
	}

	return
}
